<template>
  <el-form
      ref="formRef"
      :model="formData"
      :rules="rules"
      label-width="110px"
  >
    <el-form-item
        v-for="field in formFields"
        :key="field.prop"
        :label="field.label"
        :prop="field.prop"
    >
      <slot :name="field.prop" :row="formData">
        <el-switch
            v-if="field.type === 'switch'"
            v-model="formData[field.prop]"
            active-text="是"
            inactive-text="否"
        />

        <el-rate
            v-else-if="field.type === 'rating'"
            v-model="formData[field.prop]"
            :placeholder="'请选择' + field.label"
            show-score
        />

        <el-input
            v-else-if="['text', 'number', 'longtext'].includes(field.type)"
            v-model="formData[field.prop]"
            :placeholder="`请输入${field.label}`"
            :rows="5"
            :type="field.type === 'number' ? 'number' : (
                field.type === 'longtext' ? 'textarea' : 'text'
            )"
        />

        <!-- 文件上传 -->
        <base-upload
            v-else-if="['image', 'image-list', 'file', 'file-list'].includes(field.type)"
            v-model="formData[field.prop]"
            :accept-types="field.acceptTypes || []"
            :type="field.type"
        />

        <!-- 远程选择器 -->
        <el-select
            v-else-if="field.type === 'remote-select' || field.type === 'tag'"
            v-model="formData[field.prop]"
            :placeholder="`请选择${field.label}`"
        >
          <el-option
              v-for="opt in field.options || []"
              :key="opt.value"
              :label="opt.label"
              :value="opt.value"
          />
        </el-select>

        <!-- 日期时间选择器 -->
        <el-date-picker
            v-else-if="field.type === 'datetime'"
            v-model="formData[field.prop]"
            :placeholder="`请选择${field.label}`"
            style="width: 190px"
            type="datetime"
            value-format="YYYY-MM-DD HH:mm:ss"
        />
      </slot>
    </el-form-item>
  </el-form>
</template>

<script setup>
import {computed, ref, watch} from 'vue'
import BaseUpload from './BaseUpload.vue'
import {useStore} from "vuex";

const props = defineProps({
  // 表单字段配置
  fields: {
    type: Array,
    required: true
  },
  // 表单数据
  modelValue: {
    type: Object,
    default: () => ({})
  }
})

const emit = defineEmits(['update:modelValue', 'validate'])

const formRef = ref(null)
const formData = ref({...props.modelValue})

const store = useStore()
// 过滤不需要在表单中显示的字段
const formFields = computed(() => {
  return props.fields.filter(item => {
    if (item.formHidden) {
      return false
    }
    if (!item.hasOwnProperty('requireRoles')) {
      return true
    }
    const role = store.state.userInfo.role
    return item.requireRoles.includes(role)
  })
})

// 表单验证规则
const rules = computed(() => {
  const rulesObj = {};
  formFields.value.forEach(field => {
    if (field.hasOwnProperty('required') && !field.required) {
      return
    }
    rulesObj[field.prop] = [field.rule || {
      required: true,
      message: `请${field.type === 'tag' || field.type === 'remote-select' ? '选择' : '输入'}${field.label}`,
      trigger: ['tag', 'remote-select'].includes(field.type) ? 'change' : 'blur'
    }];
  });
  return rulesObj;
});

// 监听表单数据变化
watch(
    formData,
    (val) => {
      emit('update:modelValue', val)
    },
    {deep: true}
)

// 初始化表单数据
const initForm = async (data = {}) => {
  // 加载远程数据
  const remoteFields = props.fields.filter(field => field.type === 'remote-select')
  for (const field of remoteFields) {
    field.options = await field.api()
  }
  formData.value = {...data}
}

// 重置表单
const resetForm = () => {
  formRef.value?.resetFields()
  formData.value = {}
}

// 验证表单
const validate = () => {
  return formRef.value?.validate()
}

// 暴露方法
defineExpose({
  initForm,
  resetForm,
  validate
})
</script>

<style scoped>
</style>